package psrc.other;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * Gerador automatico de arquivos fonte java DAO e Beans.
 * 
 * Desenvolvido por lucasmachado@live.com, com ajuda de felper3d@hotmail.com
 * 
 * @author Lucas Machado
 *
 */
public class Generate {

	public static PrintStream writer;
	
	/**
	 * @param args O nome da entidade, por exemplo 'cliente'
	 */
	public static void main(String[] args) {
		
		if(args.length < 3) {
			System.out.println("Uso do programa:");
			System.out.println("\" java -jar Generate [nomeDaEntidade] [atributos]\"");
			System.out.println("\nPor exemplo:");
			System.out.println("\" java -jar Generate cliente id_cliente nome\"");
			return;
		}
		try {
			List<String> entradas = Arrays.asList(args);
			
			String[] list = new String[entradas.size()-1];
			for(int i=0; i<list.length ; i++){
				list[i] = entradas.get(i+1);
			}
			
			ArrayList<String> nomesMetodos = converteParaMetodo(list, entradas.get(0));
			
			String lowerCaseObjectName = entradas.get(0).toLowerCase();
			
			String capitalizedObjectName = capitalize(lowerCaseObjectName);
			
			
			createDAOFile(list, nomesMetodos, lowerCaseObjectName, capitalizedObjectName);
			createBeanFile(list, nomesMetodos, lowerCaseObjectName, capitalizedObjectName);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		

	}
	
	public static String fixCompostName(String name){
		while (name.contains("_")) {
			int posicao_ = name.indexOf("_");
			char charDepois = name.charAt(posicao_ + 1);
			name = name.replace("_" + charDepois, Character.toString(Character.toUpperCase(charDepois)));
		}
		name = capitalize(name);
		return name;
	}

	/**
	 * Cria arquivo java DAO
	 * @param list
	 * @param nomesMetodos
	 * @param lowerCaseObjectName
	 * @param capitalizedObjectName
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private static void createDAOFile(String[] list,
			ArrayList<String> nomesMetodos, String lowerCaseObjectName,
			String capitalizedObjectName) throws FileNotFoundException,
			IOException {
		System.out.println("[INFO] Criando arquivo \"" + fixCompostName(capitalizedObjectName) + "DAO.java\"");
		
		File javaFile = new File(fixCompostName(capitalizedObjectName)+"DAO.java");
		FileOutputStream outputStream;
		outputStream = new FileOutputStream(javaFile, false);
		writer = new PrintStream(outputStream);
		
		printDAOFile(lowerCaseObjectName, fixCompostName(capitalizedObjectName), nomesMetodos, list);
		outputStream.flush();
		outputStream.close();
		
		System.out.println("[INFO] DAO gerado com sucesso para entidade " + fixCompostName(capitalizedObjectName) + "!");
	}
	
	/** Cria arquivo java Bean
	 * @param list
	 * @param nomesMetodos
	 * @param lowerCaseObjectName
	 * @param capitalizedObjectName
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private static void createBeanFile(String[] list,
			ArrayList<String> nomesMetodos, String lowerCaseObjectName,
			String capitalizedObjectName) throws FileNotFoundException,
			IOException {
		System.out.println("[INFO] Criando arquivo \"" + fixCompostName(capitalizedObjectName) + "Bean.java\"");
		
		File javaFile = new File(fixCompostName(capitalizedObjectName)+"Bean.java");
		FileOutputStream outputStream;
		outputStream = new FileOutputStream(javaFile, false);
		writer = new PrintStream(outputStream);
		
		printBeanFile(lowerCaseObjectName, fixCompostName(capitalizedObjectName), nomesMetodos, list);
		outputStream.flush();
		outputStream.close();
		
		System.out.println("[INFO] Bean gerado com sucesso para entidade " + capitalizedObjectName + "!");
	}

	
	

	/**
	 * Deixa o primeiro caractere da String como maiusculo (capitaliza)
	 * @param text
	 * @return texto capitalizado
	 */
	private static String capitalize(String text){
		String firstChar = text.substring(0,1);
		String word = text.substring(1);
		return firstChar.toUpperCase() + word;
	}
	
	
	
	
	private static void imprimeParaOSeleciona(ArrayList<String> nomesMetodos, String[] list) {
		int i = 0;
		for(i = 1; i < nomesMetodos.size() - 1; i ++){
			writer.println("				bean.set"+ nomesMetodos.get(i) +"(rs.getString(\""+ list[i] +"\"));");
		}
		writer.println("				bean.set"+ nomesMetodos.get(0) +"(rs.getString(\""+ list[0] +"\"));");
		
	}
	
	private static void imprimeParaOAdiciona(ArrayList<String> nomesMetodos, String[] list) {
		int j = 0;
		for(int i = 1; i < nomesMetodos.size() -1; i++, j++){
			writer.println("			stmt.setString("+(j+1)+", bean.get"+ nomesMetodos.get(i) +"());");
		}
	}

	private static void imprimeParaOEdita(ArrayList<String> nomesMetodos) {
		int j = 0;
		for(int i = 1; i < nomesMetodos.size() -1; i++, j++){
			writer.println("			stmt.setString("+(j+1)+", bean.get"+ nomesMetodos.get(i) +"());");
		}
		writer.println("			stmt.setString("+(j+1)+", bean.get"+ nomesMetodos.get(0) +"());");
	}

	private static void imprimeParamAdd(String[] list) {
		writer.print("				+ \"(");
		int i = 0;
		for (i = 1; i < list.length - 1; i++) {
			writer.print(list[i] + ", ");
		}
		writer.print(list[list.length - 1]);
		writer.print(") values (");
		for (int j = 1; j < i; j++) {
			writer.print("?, ");
		}
		writer.println("?)\";");

	}
	
	private static void imprimeParamEdit(String[] list, String entidade) {
		writer.print("\"");
		for (int x = 1; x < list.length - 1; x++) {
			writer.print(list[x] + "=?, ");
		}
		writer.print(list[list.length - 1] + "=? ");
		writer.println("where " + entidade + "=?\";");
	}

	private static ArrayList<String> converteParaMetodo(String[] list, String entidade) {
		ArrayList<String> retorno = new ArrayList<String>();
		
		List<String> aProcessar = new ArrayList<String>(Arrays.asList(list));
		aProcessar.add(entidade);

		if (list != null) {
			for (String nomeBd : aProcessar) {
				String nomeMetodo = nomeBd;
				
				if (nomeMetodo.contains("_")) {
					while (nomeMetodo.contains("_")) {
						int posicao_ = nomeMetodo.indexOf("_");
						char charDepois = nomeMetodo.charAt(posicao_ + 1);
						nomeMetodo = nomeMetodo.replace("_" + charDepois, Character.toString(Character.toUpperCase(charDepois)));
					}
				}
				nomeMetodo = capitalize(nomeMetodo);
				retorno.add(nomeMetodo);
			}
		}

		return retorno;
	}
	
	private static void imprimeGettersAndSetters(String[] list){
		int i = 0;
		for(i = 1; i < list.length; i ++){
			imprimeGetter(list[i]);
			imprimeSetter(list[i]);
		}
	}
	
	private static void imprimeGetter(String nomeVar){
		writer.println("	/**");
		writer.println("	 * @return the " + nomeVar + "");
		writer.println("	 */");
		writer.println("	public String get" + fixCompostName(nomeVar) + "() {");
		writer.println("		return " + nomeVar + ";");
		writer.println("	}");
	}
	
	private static void imprimeSetter(String nomeVar){		
		writer.println("	/**");
		writer.println("	 * @param " + nomeVar + " the " + nomeVar + " to set");
		writer.println("	 */");
		writer.println("	public void set" + fixCompostName(nomeVar) + "(String " + nomeVar + ") {");
		writer.println("		this." + nomeVar + " = " + nomeVar + ";");
		writer.println("	}");
	}

	private static void imprimeVars(String[] list){
		int i = 0;
		for(i = 1; i < list.length; i ++){
			writer.println("	private String " + list[i] + ";");
		}
	}
	
	
	
	
	
	
	/**Imprime no escritor o arquivo DAO
	 * @param lowerCaseObjectName
	 * @param capitalizedObjectName
	 * @param nomesMetodos
	 * @param listaBruta
	 */
	private static void printDAOFile(String lowerCaseObjectName,
			String capitalizedObjectName, ArrayList<String> nomesMetodos, String[] listaBruta) {
		
		writer.println("package psrc.bd.dao;");
		writer.println("");
		writer.println("import java.sql.Connection;");
		writer.println("import java.sql.PreparedStatement;");
		writer.println("import java.sql.ResultSet;");
		writer.println("import java.sql.SQLException;");
		writer.println("import java.util.ArrayList;");
		writer.println("import java.util.List;");
		writer.println("");
		writer.println("import psrc.logic.util.beans." + capitalizedObjectName + "Bean;");
		writer.println("");
		writer.println("public class " + capitalizedObjectName + "DAO extends AbstractDAO {");
		writer.println("");
		writer.println("	public " + capitalizedObjectName + "DAO(Connection conn) {");
		writer.println("		super(conn);");
		writer.println("	}");
		writer.println("");
		writer.println("	@Override");
		writer.println("	public <T> void adiciona(T _bean) {");
		writer.println("		" + capitalizedObjectName + "Bean bean = (" + capitalizedObjectName + "Bean) _bean;");
		writer.println("		String sql = \"insert into " + capitalizedObjectName + " \"");
		imprimeParamAdd(listaBruta);
		writer.println("		try {");
		writer.println("			PreparedStatement stmt = connection.prepareStatement(sql);");
		writer.println("");
		imprimeParaOAdiciona(nomesMetodos, listaBruta);
		writer.println("			");
		writer.println("			stmt.execute();");
		writer.println("			stmt.close();");
		writer.println("");
		writer.println("		} catch (SQLException e) {");
		writer.println("			e.printStackTrace();");
		writer.println("		}");
		writer.println("	}");
		writer.println("");
		writer.println("	@Override");
		writer.println("	public <T> void remove(T _bean) {");
		writer.println("		" + capitalizedObjectName + "Bean bean = (" + capitalizedObjectName + "Bean) _bean;");
		writer.println("		try {");
		writer.println("			PreparedStatement stmt = connection.prepareStatement(\"delete from " + capitalizedObjectName + " where id_" + lowerCaseObjectName + "=?\");");
		writer.println("");
		writer.println("			stmt.setString(1, bean.get" + nomesMetodos.get(0) + "());");
		writer.println("");
		writer.println("			stmt.execute();");
		writer.println("			stmt.close();");
		writer.println("");
		writer.println("		} catch (SQLException e) {");
		writer.println("			e.printStackTrace();");
		writer.println("		}");
		writer.println("	}");
		writer.println("");
		writer.println("	@Override");
		writer.println("	public <T> void edita(T _bean) {");
		writer.println("		" + capitalizedObjectName + "Bean bean = (" + capitalizedObjectName + "Bean) _bean;");
		writer.println("");
		writer.print("		String sql = \"update " + capitalizedObjectName + " set \" +");
		imprimeParamEdit(listaBruta, lowerCaseObjectName);
		writer.println("		try {");
		writer.println("			PreparedStatement stmt = connection.prepareStatement(sql);");
		writer.println("");
		imprimeParaOEdita(nomesMetodos);
		writer.println("			stmt.execute();");
		writer.println("			stmt.close();");
		writer.println("		} catch (SQLException e) {");
		writer.println("			e.printStackTrace();");
		writer.println("		}");
		writer.println("	}");
		writer.println("");
		writer.println("	@Override");
		writer.println("	public <T> List<T> seleciona() {");
		writer.println("		List<" + capitalizedObjectName + "Bean> " + lowerCaseObjectName + "s = new ArrayList<" + capitalizedObjectName + "Bean>();");
		writer.println("");
		writer.println("		try {");
		writer.println("			PreparedStatement stmt = connection.prepareStatement(\"select * from " + capitalizedObjectName + "\");");
		writer.println("");
		writer.println("			ResultSet rs = stmt.executeQuery();");
		writer.println("");
		writer.println("			while (rs.next()) {");
		writer.println("				" + capitalizedObjectName + "Bean bean = new " + capitalizedObjectName + "Bean();");
		imprimeParaOSeleciona(nomesMetodos, listaBruta);
		writer.println("");
		writer.println("				" + lowerCaseObjectName + "s.add(bean);");
		writer.println("			}");
		writer.println("			rs.close();");
		writer.println("			stmt.close();");
		writer.println("			return (List<T>) " + lowerCaseObjectName + "s;");
		writer.println("		} catch (SQLException e) {");
		writer.println("			e.printStackTrace();");
		writer.println("		}");
		writer.println("		return null;");
		writer.println("	}");
		writer.println("");
		writer.println("@Override");
		writer.println("	public <T> List<T> selecionaPorId(T param) throws SQLException {");
		writer.println("		List<" + capitalizedObjectName + "Bean> " + lowerCaseObjectName + "s = new ArrayList<" + capitalizedObjectName + "Bean>();");
		writer.println("		" + capitalizedObjectName + "Bean user = (" + capitalizedObjectName + "Bean) param;");
		writer.println("		try {");
		writer.println("			PreparedStatement stmt = connection");
		writer.println("					.prepareStatement(\"select * from " + capitalizedObjectName + " where id_" + lowerCaseObjectName + "=?\");");
		writer.println("			stmt.setString(1, user.getId" + capitalizedObjectName + "());");
		writer.println("			ResultSet rs = stmt.executeQuery();");
		writer.println("			");
		writer.println("			while (rs.next()) {");
		writer.println("				" + capitalizedObjectName + "Bean bean = new " + capitalizedObjectName + "Bean();");
		imprimeParaOSeleciona(nomesMetodos, listaBruta);
		writer.println("");
		writer.println("				" + lowerCaseObjectName + "s.add(bean);");
		writer.println("			}");
		writer.println("			rs.close();");
		writer.println("			stmt.close();");
		writer.println("			return (List<T>) " + lowerCaseObjectName + "s;");
		writer.println("		} catch (SQLException e) {");
		writer.println("			e.printStackTrace();");
		writer.println("			throw e;");
		writer.println("		}");
		writer.println("	}");
		writer.println("}");
	}
	
	

	/**Imprime no escritor o arquivo Bean
	 * @param lowerCaseObjectName
	 * @param capitalizedObjectName
	 * @param nomesMetodos
	 * @param list
	 */
	private static void printBeanFile(String lowerCaseObjectName,
			String capitalizedObjectName, ArrayList<String> nomesMetodos,
			String[] list) {
		writer.println("package psrc.logic.util.beans;");
		writer.println("");
		writer.println("public class " + capitalizedObjectName + "Bean {");
		writer.println("");
		writer.println("	private String "+ list[0] +";");
		
		imprimeVars(list);
		
		writer.println("	");
		writer.println("	/**");
		writer.println("	 * @return the "+ list[0] +"");
		writer.println("	 */");
		writer.println("	public String get" + nomesMetodos.get(0) + "() {");
		writer.println("		return "+ list[0] +";");
		writer.println("	}");
		writer.println("	/**");
		writer.println("	 * @param "+ list[0] +" the "+ list[0] +" to set");
		writer.println("	 */");
		writer.println("	public void set" + nomesMetodos.get(0) + "(String "+ list[0] +") {");
		writer.println("		this."+ list[0] +" = "+ list[0] +";");
		writer.println("	}");

		imprimeGettersAndSetters(list);
		
		writer.println("	/* (non-Javadoc)");
		writer.println("	 * @see java.lang.Object#hashCode()");
		writer.println("	 */");
		writer.println("	@Override");
		writer.println("	public int hashCode() {");
		writer.println("		final int prime = 31;");
		writer.println("		int result = 1;");
		writer.println("		result = prime * result + (("+ list[0] +" == null) ? 0 : "+ list[0] +".hashCode());");
		writer.println("		return result;");
		writer.println("	}");
		writer.println("	/* (non-Javadoc)");
		writer.println("	 * @see java.lang.Object#equals(java.lang.Object)");
		writer.println("	 */");
		writer.println("	@Override");
		writer.println("	public boolean equals(Object obj) {");
		writer.println("		if (this == obj)");
		writer.println("			return true;");
		writer.println("		if (obj == null)");
		writer.println("			return false;");
		writer.println("		if (getClass() != obj.getClass())");
		writer.println("			return false;");
		writer.println("		" + capitalizedObjectName + "Bean other = (" + capitalizedObjectName + "Bean) obj;");
		writer.println("		if ("+ list[0] +" == null) {");
		writer.println("			if (other."+ list[0] +" != null)");
		writer.println("				return false;");
		writer.println("		} else if (!"+ list[0] +".equals(other."+ list[0] +"))");
		writer.println("			return false;");
		writer.println("		return true;");
		writer.println("	}");
		writer.println("	");
		writer.println("}");
		
	}

}
